package com.example.geoaimavlink_android.activity.data

import android.util.Log
import com.example.geoaimavlink_android.utils.ApiSelectUtils
import com.geoai.mavlink.geoainet.base.mavlinkcore.controller.StarLinkClientManager
import com.geoai.mavlink.geoainet.base.mavlinkcore.engine.GEOAIError
import com.geoai.mavlink.geoainet.base.mavlinkcore.interfaces.CompletionCallback
import com.geoai.mavlink.geoainet.base.mavlinkcore.interfaces.IBaseStateListener
import java.lang.reflect.Method

class MethodInvokeBuilder(private val moduleType: ChannelType, private val method: Method): IMethodInvokeBuilder {

    private val inputParamsCount: Int = method.parameterTypes.size

    private val hasReturnParams: Boolean = method.genericReturnType.toString() == "void"

    private val hasInputParams: Boolean = method.parameterTypes.isEmpty().not()

    private val isLastInputICompletionCallbackWith: Boolean = method.parameterTypes.lastOrNull()?.name?.endsWith("ICompletionCallbackWith")?:false

    private val isLastInputICompletionCallback: Boolean = method.parameterTypes.lastOrNull()?.name?.endsWith("ICompletionCallback")?:false

    private val isLastInputListener: Boolean = method.parameterTypes.lastOrNull()?.let { IBaseStateListener::class.java.isAssignableFrom(it) }?:false

    /** 当[method]为addXXXListener方法时，这个method保存removeXXXListener方法 */
    private var pairRemoveMethod: Method? = null
    /** 是否为addXXXListener方法 */
    private var isAddListenerMethod = false

    init {
        isAddListenerMethod = method.name.matches(Regex("add[^()]*Listener"))
        if(isAddListenerMethod) {
            val subStrAfterAdd = method.name.substringAfter("add", "")
            pairRemoveMethod = method.declaringClass.getDeclaredMethod("remove$subStrAfterAdd", *method.parameterTypes)
        }

    }

    override fun getMethod(): Method {
        return method
    }

    override fun methodInvoke(vararg param: Any?): Pair<Boolean, Any?> {
        val productManagerInstance = StarLinkClientManager.getInstance().productManager
        var droneID = -1
        if (productManagerInstance.iterator().hasNext()) {
            droneID = productManagerInstance.iterator().next().key
        }

        Log.i("Ronny", "droneID : ${moduleType.key}")

        val apiImplementation = ApiSelectUtils.getInstance().getApiImplementation(moduleType.key, droneID)

        var realCallMethod: Method? = method
        if(isAddListenerMethod && (param.size == 1 && param[0] == null)) {
            // 判断removeXXXListener的case
            realCallMethod = pairRemoveMethod
        }
        apiImplementation?.let {
            kotlin.runCatching {
                return Pair(true, realCallMethod?.invoke(it, *param))
            }.onFailure {
                Log.i("Ronny", "failure: ${Log.getStackTraceString(it)}") }
        }
        return Pair(false, null)
    }

    override fun isCanGet(): Boolean {
        //情况一：存在返回值
        val genericReturnType = method.genericReturnType
        if ((genericReturnType.toString() == "void").not()) return true
        //情况二：只有一个参数，并且其中含有CompletionCallback.ICompletionCallbackWith
        val parameterTypes = method.parameterTypes
        if (parameterTypes.size == 1 && parameterTypes.last().name.endsWith("ICompletionCallbackWith")) return true
        return false
    }

    override fun isCanSet(): Boolean {
        //情况一：多个参数并且参数中含有ICompletionCallback
        val parameterTypes = method.parameterTypes
        if (parameterTypes.size > 1 && parameterTypes.last().name.endsWith("ICompletionCallback")) return true
        //情况二：多个参数，并且有返回值
        val genericReturnType = method.genericReturnType
        if ((genericReturnType.toString() == "void").not() && parameterTypes.size > 0) return true
        return false
    }

    override fun isCanListener(): Boolean {
        //情况一：只有一个参数，并且参数最后的接口实例继承IBaseStateListener
        val parameterTypes = method.parameterTypes
        if (parameterTypes.size == 1 && IBaseStateListener::class.java.isAssignableFrom(parameterTypes.last())) return true
        return false
    }

    override fun isCanAction(): Boolean {
        //情况一：只有一个参数，并且参数为ICompletionCallback类型
        val parameterTypes = method.parameterTypes
        if (parameterTypes.isEmpty()) return true
        if (parameterTypes.size == 1 && parameterTypes.last().name.endsWith("ICompletionCallback")) return true
        return false
    }

    override fun actionInvoke(result: (Any) -> Unit) {
        var methodInvokeResult: Pair<Boolean, Any?>? = null

        if (hasInputParams.not()) {
            methodInvokeResult = methodInvoke()
        } else if (isLastInputICompletionCallback){
            methodInvokeResult = methodInvoke(CompletionCallback.ICompletionCallback {
                if (it == null) result.invoke("result success") else result.invoke(it)
            })
        }
        handleInvokeResult(methodInvokeResult, result)
    }

    override fun getInvoke(result: (Any) -> Unit) {
        var methodInvokeResult: Pair<Boolean, Any?>? = null

        if (hasInputParams.not() && hasReturnParams) {
            methodInvokeResult = methodInvoke()
        } else if (isLastInputICompletionCallbackWith) {
            if (inputParamsCount == 1) {
                methodInvokeResult = methodInvoke(object : CompletionCallback.ICompletionCallbackWith<Any> {
                    override fun onFailure(geoaiError: GEOAIError?) {
                        result.invoke(geoaiError?.description?:"geoai error.")
                    }

                    override fun onResult(t: Any?) {
                        t?.let { result.invoke(it) }
                    }
                })
            }
        }
        handleInvokeResult(methodInvokeResult, result)
    }

    override fun listenerInvoke(mount: Boolean, result: (Any) -> Unit) {
        var methodInvokeResult: Pair<Boolean, Any?>? = null

        if (isLastInputListener) {
            val interfaceInvoke = ApiSelectUtils.getInstance().getInterfaceInvoke(ApiSelectUtils.getInstance().getEndParamName(method))
            methodInvokeResult = methodInvoke(if (mount) interfaceInvoke else null)
        }
        handleInvokeResult(methodInvokeResult, result)
    }

    override fun setInvoke(vararg param: Any?, result: (Any) -> Unit) {
        var methodInvokeResult: Pair<Boolean, Any?>? = null

        if (inputParamsCount == 1 && isLastInputICompletionCallback) {
            methodInvokeResult = methodInvoke(CompletionCallback.ICompletionCallback {
                if (it == null) result.invoke("result success") else result.invoke(it)
            })
        } else if (isLastInputICompletionCallback) {
            methodInvokeResult = methodInvoke(*param, CompletionCallback.ICompletionCallback {
                if (it == null) result.invoke("result success") else result.invoke(it)
            })
        } else {
            methodInvokeResult = methodInvoke(*param)
        }

        handleInvokeResult(methodInvokeResult, result)
    }

    private fun handleInvokeResult(methodInvokeResult: Pair<Boolean, Any?>?, result: (Any) -> Unit) {
        methodInvokeResult?.let {methodInvoke ->
            if (methodInvoke.first) {
                result.invoke(methodInvoke.second?:"invoke func success")
            } else {
                result.invoke("invoke func failure")
            }
        }?: result.invoke("cannot invoke method in current state.")
    }


}